﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Threading;
using System.Runtime.CompilerServices;

namespace CS633_Final_Project
{
    /// <summary>
    /// This class is used to represent the movement of the robots in the environment.
    /// </summary>
	class Visualization
	{
        private const float STEPS = 20;
        private Environment playground;

        /// <summary>
        /// Default Constructor for the Visualization Class.
        /// </summary>
        /// <param name="playground"></param>
        public Visualization(Environment playground)
        {
            this.playground = playground;
        }

        /// <summary>
        /// Environment of the pursuit based evasion problem
        /// </summary>
        public Environment Playground
        {
            get { return this.playground; }
            set { this.playground = value; }
        }

        /// <summary>
        /// Moves the evader.
        /// </summary>
        /// <param name="_evader">The evader to move.</param>
        /// <param name="location">New location of the evader.</param>
        public void MoveEvader(Robot _evader, PointF location)
        {
            Robot evader = playground.Evader;
            if (!evader.Location.Equals(location))
            {
                Line path = new Line(evader.Location, location);
                ArrayList points = new ArrayList();

                Random random = new Random();
                for (int i = 0; i <= STEPS - 1; i++)
                {
                    PointF pt = findPointOnLine(path, random);
                    if (playground.InEnvironment(pt))
                    {
                        Line d = new Line(evader.Location, pt);
                        float distance_from_origin = MathUtil.SegmentLength(d);
                        KeyValuePair<float, PointF> point = new KeyValuePair<float, PointF>(distance_from_origin, pt);
                        points.Add(point);
                    }
                    else continue;
                }

                // sort points according to distance from the original point
                points.Sort(sortPointsAscending());

                // translate the pursuer through intermediate points
                foreach (KeyValuePair<float, PointF> point in points)
                {
                    PointF loc = (PointF)point.Value;
                    evader.Location = loc;
                    Thread.Sleep(500 / (int)STEPS);
                }

                // go to the final position.
                evader.Location = location;
                Thread.Sleep(500 / (int)STEPS);
            }
            else
            {
                evader.Location = location;
                Thread.Sleep(500);
            }
        }

        public void MovePursuer(Robot _pursuer, PointF location)
        {

            Robot pursuer = getPursuer(_pursuer);

            if (!pursuer.Location.Equals(location))
            {
                Line path = new Line(_pursuer.Location, location);
                ArrayList points = new ArrayList();

                Random random = new Random();
                for (int i = 0; i <= STEPS - 1; i++)
                {
                    PointF pt = findPointOnLine(path, random);
                    if (playground.InEnvironment(pt))
                    {
                        Line d = new Line(_pursuer.Location, pt);
                        float distance_from_origin = MathUtil.SegmentLength(d);
                        KeyValuePair<float, PointF> point = new KeyValuePair<float, PointF>(distance_from_origin, pt);
                        points.Add(point);
                    }
                    else continue;
                }

                // sort points according to distance from the original point
                points.Sort(sortPointsAscending());

                // translate the pursuer through intermediate points
                foreach (KeyValuePair<float, PointF> point in points)
                {
                    PointF loc = (PointF)point.Value;
                    pursuer.Location = loc;
                    Thread.Sleep(500 / (int)STEPS);
                }


                // go to the final position.
                pursuer.Location = location;
                Thread.Sleep(500 / (int)STEPS);
            }
            else
            {
                pursuer.Location = location;
                Thread.Sleep(500);
            }
        }

        /// <summary>
        /// Moves the pursuer from one location to the next smoothly.
        /// </summary>
        /// <param name="_pursuer">The pursuer.</param>
        /// <param name="locationTriangle">The new location triangle to move to.</param>
        public void MovePursuer(Robot _pursuer, Triangle locationTriangle)
        {
            Robot pursuer = getPursuer(_pursuer);

            if (!pursuer.LocationTriangle.Equals(locationTriangle))
            {
                Line path = new Line(_pursuer.Location, locationTriangle.Center);
                ArrayList points = new ArrayList();

                Random random = new Random();
                for (int i = 0; i <= STEPS - 1; i++)
                {
                    PointF pt = findPointOnLine(path, random);
                    if (playground.InEnvironment(pt))
                    {
                        Line d = new Line(_pursuer.Location, pt);
                        float distance_from_origin = MathUtil.SegmentLength(d);
                        KeyValuePair<float, PointF> point = new KeyValuePair<float, PointF>(distance_from_origin, pt);
                        points.Add(point);
                    }
                    else continue;
                }

                // sort points according to distance from the original point
                points.Sort(sortPointsAscending());

                // translate the pursuer through intermediate points
                foreach (KeyValuePair<float, PointF> point in points)
                {
                    PointF loc = (PointF)point.Value;
                    pursuer.Location = loc;
                    Thread.Sleep(500 / (int)STEPS);
                }


                // go to the final position.
                pursuer.LocationTriangle = locationTriangle;
                Thread.Sleep(500 / (int)STEPS);
            }
            else
            {
                pursuer.LocationTriangle = locationTriangle;
                Thread.Sleep(500);
            }
        }

        /// <summary>
        /// Compares points for ordering.
        /// </summary>
        /// <returns>Compares points for ordering.</returns>
        public static IComparer sortPointsAscending()
        {
            return (IComparer)new PointComparer();
        }

        [MethodImpl(MethodImplOptions.Synchronized)]
        private PointF findPointOnLine(Line line, Random random)
        {
            float y2 = line.Q.Y;
            float y1 = line.P.Y;
            float x2 = line.Q.X;
            float x1 = line.P.X;

            //slope
            float m = (y2 - y1) / (x2 - x1);

            // intercept
            float b = y1 - (m * x1);

            // find a random point
            float min_x, max_x;
            if (x2 > x1)
            {
                min_x = x1;
                max_x = x2;
            }
            else
            {
                min_x = x2;
                max_x = x1;
            }

            // get yn and xn
            float xn = random.Next((int)min_x, (int)max_x);
            float yn = (m * xn) + b;
            PointF point = new PointF(xn, yn);

            return point;
        }

        private Robot getPursuer(Robot _pursuer)
        {
            Robot pursuer = null;
            foreach (Robot p in playground.Pursuers)
            {
                if (p.Equals(_pursuer))
                {
                    pursuer = p;
                }
            }

            return pursuer;
        }
	}

    class PointComparer : IComparer
    {
        int IComparer.Compare(object a, object b)
        {
            KeyValuePair<float, PointF> aPair = (KeyValuePair<float, PointF>)a;
            KeyValuePair<float, PointF> bPair = (KeyValuePair<float, PointF>)b;
            return aPair.Key.CompareTo(bPair.Key);
        }
    }
}
